논의 사항

스토어 내부 객체를 표현하려는데, 두 가지 방법의 장단점이 있어 고민중  
개인적으로는 클래스 방식이 더 끌리긴 함ㅎㅎ

클래스 vs 함수

클래스 방식

  • 기존 코드와 스타일이 달라짐 (근데 스토어 쪼개기부터 이미 스타일이 다르긴 함..)
  • mobx observable 처리 필요 (유틸함수 프로토타이핑 중)
    • 복제 후에도 observable이 유지되는지 확인 필요 (아마 될듯)
  • (사람마다 다르겠지만 적어도 내 눈에는) 직관적으로 보임
  • lodash.clone 함수는 클래스 객체의 복제도 지원
  • 실제 private 으로 동작은 하지 않아도, 메타주석을 통해 IDE 지원은 가능
  • 다중 상속 불가 (믹스인은 가능하긴 함)
  • 자동완성, 린트 등 도구 지원이 좋음
class Card {
  /**
   * @private
   */
  $name

  /**
   * @private
   */
  $checkAmount

  /**
   * @private
   */
  $creditAmount

  constructor({creditAmt, checkAmt, istnNm}) {
    this.$name = istnNm
    this.$checkAmount = parseInt(checkAmt)
    this.$creditAmount = parseInt(creditAmt)
  }

  get name() {
    return this.$name
  }

  get creditAmount() {
    return this.$creditAmount
  }

  get checkAmount() {
    return this.$checkAmount
  }

  set checkAmount(newCheckAmount) {
    this.$checkAmount = newCheckAmount
  }

  get totalAmount() {
    return this.checkAmount + this.creditAmount
  }

  addOverduePanalty() {
    this.checkAmount += OVERDUE_PANALTY
  }
}

// decorator 문법을 사용하지 않기 때문에, 별도로 처리 필요
decorate(Card, {
  $name: observable,
  $checkAmount: observable,
  $creditAmount: observable,
  name: computed,
  creditAmount: computed,
  checkAmount: computed,
  totalAmount: computed,
  addOverduePanalty: action,
})

/*
위 과정을 조금 더 간단히 줄여주는 유틸 정도는 작성 가능할 듯
예상 인터페이스: autoDecorate(Card, ['$name', '$checkAmount', '$creditAmount])
*/

// 만약 상속이 필요하다면 클래스 자체를 export 해야 함
export const createCard = (cardData) => new Card(cardData)

함수 방식

  • 기존 코드와 스타일이 비슷
  • 믹스인이 간단 (자주 필요할지는 잘 모르겠음;)
  • private field를 클로저로 숨길 수 있음
  • 타입 확인 어려움
  • 복제 이슈
    • 복제시 getter/setter 제대로 복제 안됨
      • getter/setter 사용 안하고 그냥 다 프로퍼티로 때려넣으면 괜찮음;
    • lodash.clone 해도 같은 내부에서 클로저를 보고 있어서 private 변수를 공유
      • lodash.cloneWith + clone 함수로 회피 가능하긴 함
      • 하지만 비 직관적..
  • prototype chaining 이 없으므로 메모리 더 소비
    • 불필요할 수 있는 클로저 다수 유지

export const createCard = ({creditAmt, checkAmt, istnNm}) => {
  let $checkAmount = parseInt(checkAmt) // Mutable
  const $creditAmount = parseInt(creditAmt) // Immutable

  return {
    get name() {
      return istnNm
    },

    get creditAmount() {
      return $creditAmount
    },

    get checkAmount() {
      return $checkAmount
    },

    set checkAmount(newCheckAmount) {
      $checkAmount = newCheckAmount
    },

    get totalAmount() {
      return this.creditAmount + this.checkAmount
    },

    addOverduePanalty() {
      this.checkAmount += OVERDUE_PANALTY
    },

    // 필요한 이유는 "단점" 에서 설명
    clone() {
      return createCard({creditAmt, checkAmt, istnNm})
    },
  }
}

기타

  • 근데 스토어에서만 사용할거면 복제가 굳이 필요 없을수도 있음

    • 대부분의 경우 스토어의 값을 변경하는건, 모든 곳에서 변경이 일어나게 하려는 목적일듯..
    • 컴포넌트에서 값을 표현하기 위해 sort 등의 함수를 사용하는 경우 필요함 (사이드이펙트)
      • 단순히 리스트만 복제하면 문제 없긴 함
    • 근데 왤케 찝찝하지;;
const card = createCard({
  creditAmt: '0',
  checkAmt: '1000',
  istnNm: '네이버카드',
})

const cloneOfCard = _.cloneWith(card, (target) => {
  if (typeof target.clone === 'function') {
    return target.clone()
  }
})

results matching ""

    No results matching ""